大家好啊,今天的鐵人賽要來介紹我們如何在ASP.NET Core 發送電子郵件。我們的應用程序將以純文本的形式來發送郵件,也支持附件的功能,我們還會知道如何用HTML的模板來發送郵件,這次的功能我們要先去使用MailKit 的第三方套件
當我們要發送郵件,我們需要一個服務器。現在設置自己的服務器/應用程序來做到這一點是不切實際的。因此,我們使用其他提供商的服務器。最受歡迎的當然是 Gmail。在我們的例子中,主機是指 SMTP 服務器
SMTP: SMTP 或簡單郵件傳輸協議服務器主要目的是發送和接收郵件的應用程序。當您發送電子郵件時,SMTP 服務器會確定目標域並將郵件中繼到相應的服務器
SMTP需要內容
這裡如何啟用安全驗證跟應用程式密碼我就不多說,起參考下面連結
https://shinher.gitbook.io/shinher/ru-he-shen-qing-ying-yong-cheng-shi-zhuan-yong-mi-ma
接著我們去新增兩個模型,一個要來放我們要發送的信箱、主題、正文與附件等參數,另一個釋放寄件人的模型
請求模組
public class MailRequest
{
public string ToEmail { get; set; }
public string Subject { get; set; }
public string Body { get; set; }
public List<IFormFile> Attachments { get; set; }
}
寄件人模組
public class MailSettings
{
public string Mail { get; set; }
public string DisplayName { get; set; }
public string Password { get; set; }
public string Host { get; set; }
public int Port { get; set; }
}
這兩個模組我是把他們放在Models/MailSetting.cs 裡
接著我們到appsettings.json 裡先去設定我們寄件人的設定
"MailSettings": {
"Mail": "<fromemail>",
"DisplayName": "<displayname>",
"Password": "<yourpasswordhere>",
"Host": "smtp.gmail.com",
"Port": 587
}
像之前我們要取appsetting.json 的資料時都去要builder.Configuration.GetConnectionString()
這樣一個一個去拿,這樣的方式很麻煩也很佔空間,所以在這裡我們有另一種方式更好去拿MailSettings 內的值
先去註冊組態注入服務
builder.Services.Configure<MailSettings>(builder.Configuration.GetSection("MailSettings"));
這裡GetSection
方法可根據 key 取得某區塊的組態物件,並回傳一個代表組態區塊的 IConfigurationSection
,而 Configure<T>
則需要給定一個代表組態資訊的 IConfiguration
,由於 IConfigurationSection
實作了 IConfiguration
介面,所以這邊我們可以直接將 GetSection
的結果作為參數傳入
再來我們可以使用IOptions<T>
的方式進行注入
先去創個interface來當發郵寄的功能,Helper/IMailService.cs
public interface IMailService
{
Task SendEmailiAsync(MailRequest mailRequest);
}
接著就是功能的部分,Helper/MailService.cs
記得要去繼承剛才的IMailService
public class MailService : IMailService
{
// ...
}
在建構函數時就會先把appsetting.json 裡的值抓近來,透過參數IOptions<MailSettings>
來把剛才註冊的Configure
裡提供的Value來把對應的key 放入
private readonly MailSettings _mailSettings;
public MailService(IOptions<MailSettings> mailSettings)
{
_mailSettings = mailSettings.Value;
}
實際跑程式後可以看到appsetting.json 的值真的有被套用近來
最後就剩功能的地方,在這裡我把它分成三的部分
public async Task SendEmailiAsync(MailRequest mailRequest)
{
// 寄/發送人的資訊
var email = new MimeMessage();
email.Sender = MailboxAddress.Parse(_mailSettings.Mail);
email.To.Add(MailboxAddress.Parse(mailRequest.ToEmail));
email.Subject = mailRequest.Subject; // 主題
//=============================================================
//發送內容
var builder = new BodyBuilder();
if(mailRequest.Attachments != null) // 事處理檔案的部分
{
byte[] fileBytes;
foreach (var file in mailRequest.Attachments)
{
if (file.Length > 0)
{
using (var ms = new MemoryStream())
{
file.CopyTo(ms);
fileBytes = ms.ToArray();
}
builder.Attachments.Add(file.FileName, fileBytes, ContentType.Parse(file.ContentType));
}
}
}
builder.HtmlBody = mailRequest.Body; // 郵件訊息內容
email.Body = builder.ToMessageBody();
//=============================================================
//smtp的寄送方式(使用appsetting.json的資訊)
using var smtp = new SmtpClient();
smtp.Connect(_mailSettings.Host, _mailSettings.Port, SecureSocketOptions.StartTls);
smtp.Authenticate(_mailSettings.Mail, _mailSettings.Password);
await smtp.SendAsync(email);
smtp.Disconnect(true);
}
接著我們就去套用剛才寫好的功能
[Route("api/[controller]")]
[ApiController]
public class MailController : ControllerBase
{
// 套用Mail的Method
private readonly IMailService _mailService;
public MailController(IMailService mailService)
{
_mailService = mailService;
}
[HttpPost("send")]
public async Task<IActionResult> SendMail([FromForm]MailRequest request)// 這裡因為有檔案所以要使用`[FromForm]`
{
try
{
await _mailService.SendEmailiAsync(request);
return Ok();
}
catch(Exception)
{
throw;
}
}
}
特別注意,記得要去註冊剛剛的功能,不然你會一直報錯
builder.Services.AddSingleton<IMailService, MailService>();
最後去跑你要寄的email應該就行了
今天的鐵人賽就先到這裡啦,還剩三天再撐過就可以輕鬆了,希望大家會喜歡今天的主題~~~
參考資料: